<?php

namespace App\Service;

use App\Constants\ErrorCode;
use App\Constants\RedisKey;
use App\Exception\CommonException;
use App\Model\AdminAuthGroupAccess;
use App\Model\AdminAuthRule;
use App\Model\AdminMenu;
use App\Model\AdminUserData;
use Hyperf\Config\Annotation\Value;
use Hyperf\Context\ApplicationContext;
use Hyperf\Redis\RedisFactory;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;

class LoginService {

    #[Value('apiadmin.online_time')]
    private int $online_time;

    /**
     * 执行用户登录
     * @param $userInfo
     * @param $ip
     * @return array
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    public function doLogin($userInfo, $ip): array {
        $redis = ApplicationContext::getContainer()->get(RedisFactory::class)->get('default');

        if ($userInfo->getAttribute('status')) {
            //更新用户数据
            $userData = $userInfo->userData;
            $userInfo = $userInfo->toArray();

            $has = $redis->exists(RedisKey::ADMIN_LOGIN_ID . ':' . $userInfo['id']);
            if ($has) {
                $msg     = '多用户登录，已自动踢出上一个用户';
                $apiAuth = $redis->get(RedisKey::ADMIN_LOGIN_ID . ':' . $userInfo['id']);
                $redis->del(RedisKey::ADMIN_LOGIN_AUTH . ':' . $apiAuth);
            } else {
                $msg = '登录成功';
            }

            if ($userData) {
                $userData->login_times++;
                $userData->last_login_ip   = sprintf("%u", ip2long($ip));
                $userData->last_login_time = time();
            } else {
                $userData                          = new AdminUserData();
                $userData->login_times             = 1;
                $userData->uid                     = $userInfo['id'];
                $userData->last_login_ip           = sprintf("%u", ip2long($ip));
                $userData->last_login_time         = time();
                $userData->head_img                = '';
                $userInfo['user_data']['head_img'] = '';
            }
            $userData->save();

            $userInfo['access'] = $this->getAccess($userInfo['id']);
            $userInfo['menu']   = $this->getAccessMenuData($userInfo['id']);
            $apiAuth            = md5(uniqid('', true) . time());

            $redis = ApplicationContext::getContainer()->get(RedisFactory::class)->get('default');
            $redis->set(RedisKey::ADMIN_LOGIN_AUTH . ':' . $apiAuth, json_encode($userInfo), $this->online_time);
            $redis->set(RedisKey::ADMIN_LOGIN_ID . ':' . $userInfo['id'], $apiAuth, $this->online_time);
            $userInfo['apiAuth'] = $apiAuth;

            return [$userInfo, $msg];
        }

        throw new CommonException("用户已被封禁，请联系管理员", ErrorCode::LOGIN_ERROR);
    }

    /**
     * 获取当前用户的允许菜单
     * @param int $uid
     * @return array
     * @author zhaoxiang <zhaoxiang051405@gmail.com>
     */
    public function getAccessMenuData(int $uid): array {
        $returnData = [];
        $isSupper   = ToolService::isAdministrator($uid);
        if ($isSupper) {
            $access     = AdminMenu::query()->get();
            $returnData = ToolService::listToTree(ToolService::buildArrFromObj($access));
        } else {
            $groups = AdminAuthGroupAccess::query()->where('uid', $uid)->first();
            if (!empty($groups) && $groups->getAttribute('group_id')) {
                $access     = AdminAuthRule::query()->whereIn('group_id', explode(',', $groups->getAttribute('group_id')))->get();
                $access     = array_unique(array_column(ToolService::buildArrFromObj($access), 'url'));
                $access[]   = "";
                $menus      = AdminMenu::query()->whereIn('url', $access)->get();
                $returnData = ToolService::listToTree(ToolService::buildArrFromObj($menus));
            }
        }

        return array_values($returnData);
    }

    /**
     * 获取用户权限数据
     * @param int $uid
     * @return array
     */
    private function getAccess(int $uid): array {
        $isSupper = ToolService::isAdministrator($uid);
        if ($isSupper) {
            $access = AdminMenu::all();
            $access = ToolService::buildArrFromObj($access);

            return array_values(array_filter(array_column($access, 'url')));
        }

        $groups = AdminAuthGroupAccess::query()->where('uid', $uid)->first();
        if (!empty($groups) && $groups->getAttribute('group_id')) {
            $access = AdminAuthRule::query()->whereIn('group_id', explode(',', $groups->getAttribute('group_id')))->get();
            $access = ToolService::buildArrFromObj($access);

            return array_values(array_unique(array_column($access, 'url')));
        }

        return [];
    }
}
